package android.money.network;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import android.money.Sync;
import android.money.TransactionConfirm;
import android.money.data.Account;
import android.money.data.Protocol;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;

public class SyncConnection implements Runnable {

	private boolean startPay = false;
	private boolean isDisconnected = false;

	private Sync sync;

	private String host;

	private int port = 5432;

	private Socket socket;

	private DataOutputStream dos;

	private DataInputStream dis;

	private Message msg;

	private TransactionConfirm tc;
	
	private String phoneNumber;

	public SyncConnection(Sync sync ,String phoneNumber) {
		this.sync = sync;
		this.phoneNumber = phoneNumber;
		msg = new Message();
	}

	public void run() {
		if (connectToPos()) {
			while (!startPay);
			if(!isDisconnected)
				startPay();
		}
	}

	public void disconnectToPos() {
		try {
			dos.writeUTF(genCommand(Protocol.MSG_BYE, Protocol.DATA_OK));
			dis.close();
			dos.close();
			socket.close();
			isDisconnected = true;
			setStartPay();
		} catch (Exception e) {
		}
	}

	private void startPay() {
		String paymentCommand = "";
		Account account = tc.getPayAccount();
		paymentCommand += genCommand(Protocol.CARD_NUM, account.getNumber());
		paymentCommand += genCommand(Protocol.CARD_SECCODE, account
				.getSec_code());
		paymentCommand += genCommand(Protocol.CARD_EXP_MONTH, account
				.getExpire_month()
				+ "");
		paymentCommand += genCommand(Protocol.CARD_EXP_YEAR, account
				.getExpire_year()
				+ "");
		paymentCommand += genCommand(Protocol.CARD_TYPE, account.getType()
				.toString());
		paymentCommand += genCommand(Protocol.CARD_NAME, account
				.getHolderName());
		msg = new Message();
		try {
			dos.writeUTF(paymentCommand);
			String ackMsg = dis.readUTF();
			Map<String, String> ackCommand = parseCommand(ackMsg);
			if (ackCommand.containsKey(Protocol.MSG_ACK)
					&& ackCommand.get(Protocol.MSG_ACK)
							.equals(Protocol.DATA_OK)) {
				msg.what = TransactionConfirm.PAY_SUCCESS;
			} else
				throw new Exception("Invalid account");

		} catch (Exception e) {
			msg.what = TransactionConfirm.PAY_FAIL;
			msg.obj = e.getMessage();
		}
		tc.payHandler.sendMessage(msg);
	}

	public void setStartPay() {
		startPay = true;
	}

	public void setTransactionConfirm(TransactionConfirm tc) {
		this.tc = tc;
	}

	public String getAddress() {
		return socket.getInetAddress().getHostAddress();
	}

	private boolean connectToPos() {
		try {
			host = sync.getHost();
			socket = new Socket(host, port);
			dos = new DataOutputStream(socket.getOutputStream());
			dis = new DataInputStream(socket.getInputStream());
			dos.writeUTF(genCommand(Protocol.MSG_JOIN, phoneNumber));
			Map<String, String> ackMsg = parseCommand(dis.readUTF());
			if (ackMsg.containsKey(Protocol.MSG_ACK)
					&& ackMsg.get(Protocol.MSG_ACK).equals(Protocol.DATA_OK)) {
				Map<String, String> paymentDetail = parseCommand(dis.readUTF());
				if (paymentDetail.containsKey(Protocol.PAY_AMOUNT)
						&& paymentDetail.containsKey(Protocol.PAY_UNIT)) {
					msg.what = Sync.SYNCS_SUCCESS;
					msg.obj = paymentDetail;
					sync.syncHandler.sendMessage(msg);
					return true;
				}
			}
			throw new Exception("UNKNOWN REASON");
		} catch (Exception e) {
			msg.what = Sync.SYNCS_FAIL;
			msg.obj = e.getMessage();
			sync.syncHandler.sendMessage(msg);
			return false;
		}
	}

	private Map<String, String> parseCommand(String txt) {
		Map<String, String> dataMap = new HashMap<String, String>();
		String datas[] = txt.split(";");
		for (String data : datas) {
			String header = data.split(":")[0].trim();
			String msg = data.split(":")[1].trim();
			dataMap.put(header, msg);
		}
		return dataMap;
	}

	private String genCommand(String key, String value) {
		return key + ":" + value + ";";
	}

}
